﻿using System.Collections.Generic;
using System.Linq;

namespace dPet.Application.Services.Implementation
{
	using AutoMapper;
	using dPet.Application.DataObjects;
	using dPet.Domain.Models;
	using dPet.Domain.Repositories;
	using dPet.Domain.Services;
	using dPet.Domain.Specifications;
	using dPet.Infrastructure.Logging;
	using Hangerd;
	using Hangerd.Extensions;
	using Hangerd.Repository;

	public class ServingService : ServiceBase, IServingService
	{
		#region Repository

		private readonly IHospitalRepository _hospitalRepository;
		private readonly IServiceItemSKURepository _serviceItemSKURepository;
		private readonly IServiceOrderRepository _serviceOrderRepository;

		#endregion

		#region Services

		private readonly IServingDomainService _servingDomainService;

		#endregion

		#region Constructors

		public ServingService(
			IRepositoryContext unitOfWork,
			IHospitalRepository hospitalRepository,
			IServiceItemSKURepository serviceItemSKURepository,
			IServiceOrderRepository serviceOrderRepository,
			IServingDomainService servingDomainService)
			: base(unitOfWork)
		{
			_hospitalRepository = hospitalRepository;
			_serviceItemSKURepository = serviceItemSKURepository;
			_serviceOrderRepository = serviceOrderRepository;
			_servingDomainService = servingDomainService;
		}

		#endregion

		#region ServiceOrder

		public MessagedResult<ServiceOrderDto> CreateServiceOrder(string hospitalId, MembershipLevelDto membershipLevelDto, ShoppingCartItemDto[] items, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "服务订单管理", "创建订单", (ref ServiceOrder order) =>
			{
				if (items == null || items.Length == 0)
				{
					throw new HangerdException("服务项列表为空");
				}

				var hospital = _hospitalRepository.Get(hospitalId, false);

				if (hospital == null)
				{
					throw new HangerdException("医院信息不存在");
				}

				var skuFound = new Dictionary<string, ServiceItemSKU>(items.Length);
				var shoppingCart = new List<ShoppingCartItem<ServiceItemSKU>>();

				foreach (var item in items)
				{
					if (!skuFound.ContainsKey(item.ItemId))
					{
						var sku = _serviceItemSKURepository.Get(item.ItemId, true, sisku => sisku.ServiceItem);

						if (sku == null)
						{
							throw new HangerdException("服务项SKU读取异常:{0}", item.ItemId);
						}

						skuFound.Add(item.ItemId, sku);
					}

					shoppingCart.Add(new ShoppingCartItem<ServiceItemSKU>(skuFound[item.ItemId], item.Quantity));
				}

				order = _servingDomainService.CreateServiceOrder(hospital, (MembershipLevel)membershipLevelDto, shoppingCart, @operator.LoginName);

				_serviceOrderRepository.Add(order, true);
				
				UnitOfWork.Commit();

				return Mapper.Map<ServiceOrder, ServiceOrderDto>(order);
			}, successMessage: "下单成功");
		}

		public IEnumerable<ServiceOrderDto> GetServiceOrders(string hospitalId, ServiceOrderDto queryDto,
			int pageIndex, int pageSize, out int totalNumber)
		{
			var spec = ServiceOrderSpecifications.HospitalIdEquals(hospitalId);

			if (queryDto != null)
			{
				spec &= ServiceOrderSpecifications.StatusEquals((OrderStatus)queryDto.Status);

				if (!string.IsNullOrWhiteSpace(queryDto.OrderNumber))
				{
					spec &= ServiceOrderSpecifications.OrderNumberEquals(queryDto.OrderNumber);
				}
			}

			var orders = _serviceOrderRepository.GetAll(spec, false)
				.OrderByDescending(c => c.CreateTime)
				.Paging(pageIndex, pageSize, out totalNumber);

			return Mapper.Map<IEnumerable<ServiceOrder>, IEnumerable<ServiceOrderDto>>(orders);
		}

		public ServiceOrderDto GetServiceOrder(string orderId)
		{
			var order = _serviceOrderRepository.Get(orderId, false, so => so.OrderLines);

			return Mapper.Map<ServiceOrder, ServiceOrderDto>(order);
		}

		public ServiceOrderDto GetServiceOrder(string orderId, OrderStatusDto statusDto)
		{
			var spec = ServiceOrderSpecifications.IdEquals(orderId)
				& ServiceOrderSpecifications.StatusEquals((OrderStatus)statusDto);

			var order = _serviceOrderRepository.Get(spec, false, so => so.OrderLines);

			return Mapper.Map<ServiceOrder, ServiceOrderDto>(order);
		}

		public MessagedResult<bool> PayServiceOrder(string orderId, PaymentMethodDto paymentMethodDto, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "服务订单管理", "支付订单", (ref ServiceOrder order) =>
			{
				order = _serviceOrderRepository.Get(orderId, true);

				if (order == null)
				{
					throw new HangerdException("订单信息不存在");
				}

				order.Complete((PaymentMethod)paymentMethodDto, @operator.LoginName);

				_serviceOrderRepository.Update(order, true);
				
				UnitOfWork.Commit();

				return true;
			});
		}

		public MessagedResult<bool> CancelServiceOrder(string orderId, IOperator @operator)
		{
			return TryLoggedOperate(@operator, "服务订单管理", "取消订单", (ref ServiceOrder order) =>
			{
				order = _serviceOrderRepository.Get(orderId, true);

				if (order == null)
				{
					throw new HangerdException("订单信息不存在");
				}

				//取消订单
				order.Cancel(@operator.LoginName);

				_serviceOrderRepository.Update(order, true);
				
				UnitOfWork.Commit();

				return true;
			});
		}

		#endregion
	}
}
